﻿using System.Collections.ObjectModel;
using System.Text.Json;

namespace TimeSpan.Utilities;

public static class Extensions {

    /// <summary>在后面追加一组数据</summary>
    public static ICollection<T> AppendRange<T>(this ICollection<T> source, IEnumerable<T> datas) {
        foreach (var data in datas) {
            source.Add(data);
        }
        return source;
    }

    /// <summary>在前面追加一组数据</summary>
    public static ObservableCollection<T> PrependRange<T>(this ObservableCollection<T> source, IEnumerable<T> datas) {
        foreach (var data in datas) {
            source.Insert(0, data);
        }
        return source;
    }

    /// <summary>用新的一组数据替换现有的全部数据</summary>
    public static ICollection<T> Reset<T>(this ICollection<T> source, IEnumerable<T> datas) {
        var newData = datas.ToList();
        source.Clear();
        return source.AppendRange(newData);
    }

    /// <summary>用一个新的数据替换一个旧的数据，位置不变</summary>
    public static ObservableCollection<T> Replace<T>(this ObservableCollection<T> source, T oldItem, T newItem) {
        var index = source.IndexOf(oldItem);
        source.RemoveAt(index);
        source.Insert(index, newItem);
        return source;
    }

    /// <summary>移除满足条件的数据</summary>
    public static ICollection<T> RemoveWhere<T>(this ICollection<T> source, Func<T, bool> condition) {
        foreach (var item in source.Where(condition).ToList()) {
            source.Remove(item);
        }
        return source;
    }

    /// <summary>根据源对象的属性创建record类型的目标对象，返回目标对象</summary>
    public static TTarget CopyPropertiesToRecord<TTarget>(this object source) where TTarget : class {
        var sourceProps = source.GetType().GetProperties().Select(x => new { x.PropertyType, x.Name, Value = x.GetValue(source) }).ToArray();
        var parameters = typeof(TTarget).GetConstructors().Where(x => x.IsPublic).First().GetParameters().Select(x => new { x.ParameterType, x.Name });
        var result = (TTarget)Activator.CreateInstance(typeof(TTarget), parameters.Select(x => sourceProps.SingleOrDefault(y => y.Name == x.Name)?.Value ?? default).ToArray())!;
        return result.CopyPropertiesFrom(source);
    }

    /// <summary>从目标对象中复制同名属性值到源对象中，返回源对象</summary>
    public static TSource CopyPropertiesFrom<TSource, TTarget>(this TSource source, TTarget target) {
        var propsSource = typeof(TSource).GetProperties().Where(x => x.CanWrite).Select(x => x.Name);
        var propsTarget = typeof(TTarget).GetProperties().Where(x => x.CanRead).Select(x => x.Name);

        var propsCommon = propsSource.Intersect(propsTarget);

        foreach (var prop in propsCommon) {
            try {
                var value = typeof(TTarget).GetProperty(prop)!.GetValue(target);
                typeof(TSource).GetProperty(prop)!.SetValue(source, value);
            } catch {
                continue;
            }
        }

        return source;
    }

    /// <summary>从源对象中复制属性到目标对象中，返回目标对象</summary>
    public static TTarget CopyPropertiesTo<TSource, TTarget>(this TSource source, TTarget target) {
        return target.CopyPropertiesFrom(source);
    }

    /// <summary>根据源对象的属性创建目标对象，返回目标对象</summary>
    public static TTarget CopyPropertiesTo<TTarget>(this object source) where TTarget : new() {
        var target = new TTarget();
        return target.CopyPropertiesFrom(source);
    }

    /// <summary>使用(T)obj将对象转换为指定类型，转换失败则返回null</summary>
    public static T? As<T>(this object obj) {
        try {
            return (T)obj;
        } catch {
            return default;
        }
    }

    /// <summary>使用(T)obj将对象转换为指定类型</summary>
    public static T AsTrue<T>(this object obj) {
        return (T)obj;
    }

    /// <summary>使用(T)obj将对象转换为指定类型</summary>
    public static TTarget As<TSocrce, TTarget>(this TSocrce obj) where TSocrce : TTarget {
        return obj;
    }

    /// <summary>Json克隆，简单替代深拷贝</summary>
    public static T? JsonClone<T>(this T obj) {
        return JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(obj));
    }

    /// <summary>Json克隆，简单替代深拷贝</summary>
    public static object? JsonClone(this object obj) {
        var jsonText = JsonSerializer.Serialize(obj);
        return JsonSerializer.Deserialize(jsonText, obj.GetType());
    }

    /// <summary>获取底层异常</summary>
    public static Exception GetInnestException(this Exception ex) {
        return ex.InnerException == null ? ex : GetInnestException(ex.InnerException);
    }

}